home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Freeware 2002 November
/
SGI Freeware 2002 November - Disc 1.iso
/
dist
/
fw_emacs-lisp-intro.idb
/
usr
/
freeware
/
info
/
emacs-lisp-intro.info-7.z
/
emacs-lisp-intro.info-7
Wrap
Text File
|
2002-07-08
|
48KB
|
1,199 lines
This is emacs-lisp-intro.info, produced by makeinfo version 4.0b from
emacs-lisp-intro.texi.
INFO-DIR-SECTION Emacs
START-INFO-DIR-ENTRY
* Emacs Lisp Intro: (eintr).
A simple introduction to Emacs Lisp programming.
END-INFO-DIR-ENTRY
This is an introduction to `Programming in Emacs Lisp', for people
who are not programmers.
Edition 2.04, 2001 Dec 17
Copyright (C) 1990, '91, '92, '93, '94, '95, '97, 2001 Free Software
Foundation, Inc.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1 or
any later version published by the Free Software Foundation; with the
Invariant Section being the Preface, with the Front-Cover Texts being
no Front-Cover Texts, and with the Back-Cover Texts being no Back-Cover
Texts. A copy of the license is included in the section entitled "GNU
Free Documentation License".
File: emacs-lisp-intro.info, Node: kill-new function, Prev: kill-append function, Up: copy-region-as-kill body
The `kill-new' function
.......................
The `kill-new' function looks like this:
(defun kill-new (string &optional replace)
"Make STRING the latest kill in the kill ring.
Set the kill-ring-yank pointer to point to it.
If `interprogram-cut-function' is non-nil, apply it to STRING.
Optional second argument REPLACE non-nil means that STRING will replace
the front of the kill ring, rather than being added to the list."
(and (fboundp 'menu-bar-update-yank-menu)
(menu-bar-update-yank-menu string (and replace (car kill-ring))))
(if (and replace kill-ring)
(setcar kill-ring string)
(setq kill-ring (cons string kill-ring))
(if (> (length kill-ring) kill-ring-max)
(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
(setq kill-ring-yank-pointer kill-ring)
(if interprogram-cut-function
(funcall interprogram-cut-function string (not replace))))
As usual, we can look at this function in parts.
The first line of the documentation makes sense:
Make STRING the latest kill in the kill ring.
Let's skip over the rest of the documentation for the moment.
Also, let's skip over the first two lines of code, those involving
`menu-bar-update-yank-menu'. We will explain them below.
The critical lines are these:
(if (and replace kill-ring)
;; then
(setcar kill-ring string)
;; else
(setq kill-ring (cons string kill-ring))
(if (> (length kill-ring) kill-ring-max)
;; avoid overly long kill ring
(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
(setq kill-ring-yank-pointer kill-ring)
(if interprogram-cut-function
(funcall interprogram-cut-function string (not replace))))
The conditional test is `(and replace kill-ring)'. This will be
true when two conditions are met: the kill ring has something in it,
and the `replace' variable is true.
The `kill-append' function sets `replace' to be true; then, when the
kill ring has at least one item in it, the `setcar' expression is
executed:
(setcar kill-ring string)
The `setcar' function actually changes the first element of the
`kill-ring' list to the value of `string'. It replaces the first
element.
On the other hand, if the kill ring is empty, or replace is false,
the else-part of the condition is executed:
(setq kill-ring (cons string kill-ring))
(if (> (length kill-ring) kill-ring-max)
(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
This expression first constructs a new version of the kill ring by
prepending `string' to the existing kill ring as a new element. Then
it executes a second `if' clause. This second `if' clause keeps the
kill ring from growing too long.
Let's look at these two expressions in order.
The `setq' line of the else-part sets the new value of the kill ring
to what results from adding the string being killed to the old kill
ring.
We can see how this works with an example:
(setq example-list '("here is a clause" "another clause"))
After evaluating this expression with `C-x C-e', you can evaluate
`example-list' and see what it returns:
example-list
=> ("here is a clause" "another clause")
Now, we can add a new element on to this list by evaluating the
following expression:
(setq example-list (cons "a third clause" example-list))
When we evaluate `example-list', we find its value is:
example-list
=> ("a third clause" "here is a clause" "another clause")
Thus, the third clause was added to the list by `cons'.
This is exactly similar to what the `setq' and `cons' do in the
function. Here is the line again:
(setq kill-ring (cons string kill-ring))
Now for the second part of the `if' clause. This expression keeps
the kill ring from growing too long. It looks like this:
(if (> (length kill-ring) kill-ring-max)
(setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
The code checks whether the length of the kill ring is greater than
the maximum permitted length. This is the value of `kill-ring-max'
(which is 60, by default). If the length of the kill ring is too long,
then this code sets the last element of the kill ring to `nil'. It
does this by using two functions, `nthcdr' and `setcdr'.
We looked at `setcdr' earlier (*note `setcdr': setcdr.). It sets
the CDR of a list, just as `setcar' sets the CAR of a list. In this
case, however, `setcdr' will not be setting the CDR of the whole kill
ring; the `nthcdr' function is used to cause it to set the CDR of the
next to last element of the kill ring--this means that since the CDR of
the next to last element is the last element of the kill ring, it will
set the last element of the kill ring.
The `nthcdr' function works by repeatedly taking the CDR of a
list--it takes the CDR of the CDR of the CDR ... It does this N times
and returns the results.
Thus, if we had a four element list that was supposed to be three
elements long, we could set the CDR of the next to last element to
`nil', and thereby shorten the list.
You can see this by evaluating the following three expressions in
turn. First set the value of `trees' to `(maple oak pine birch)', then
set the CDR of its second CDR to `nil' and then find the value of
`trees':
(setq trees '(maple oak pine birch))
=> (maple oak pine birch)
(setcdr (nthcdr 2 trees) nil)
=> nil
trees
=> (maple oak pine)
(The value returned by the `setcdr' expression is `nil' since that is
what the CDR is set to.)
To repeat, in `kill-new', the `nthcdr' function takes the CDR a
number of times that is one less than the maximum permitted size of the
kill ring and sets the CDR of that element (which will be the rest of
the elements in the kill ring) to `nil'. This prevents the kill ring
from growing too long.
The next to last expression in the `kill-new' function is
(setq kill-ring-yank-pointer kill-ring)
The `kill-ring-yank-pointer' is a global variable that is set to be
the `kill-ring'.
Even though the `kill-ring-yank-pointer' is called a `pointer', it
is a variable just like the kill ring. However, the name has been
chosen to help humans understand how the variable is used. The
variable is used in functions such as `yank' and `yank-pop' (*note
Yanking Text Back: Yanking.).
Now, to return to the first two lines in the body of the function:
(and (fboundp 'menu-bar-update-yank-menu)
(menu-bar-update-yank-menu string (and replace (car kill-ring))))
This is an expression whose first element is the function `and'.
The `and' special form evaluates each of its arguments until one of
the arguments returns a value of `nil', in which case the `and'
expression returns `nil'; however, if none of the arguments returns a
value of `nil', the value resulting from evaluating the last argument
is returned. (Since such a value is not `nil', it is considered true
in Emacs Lisp.) In other words, an `and' expression returns a true
value only if all its arguments are true.
In this case, the expression tests first to see whether
`menu-bar-update-yank-menu' exists as a function, and if so, calls it.
The `fboundp' function returns true if the symbol it is testing has a
function definition that `is not void'. If the symbol's function
definition were void, we would receive an error message, as we did when
we created errors intentionally (*note Generate an Error Message:
Making Errors.).
Essentially, the `and' is an `if' expression that reads like this:
if THE-MENU-BAR-FUNCTION-EXISTS
then EXECUTE-IT
`menu-bar-update-yank-menu' is one of the functions that make it
possible to use the `Select and Paste' menu in the Edit item of a menu
bar; using a mouse, you can look at the various pieces of text you have
saved and select one piece to paste.
Finally, the last expression in the `kill-new' function adds the
newly copied string to whatever facility exists for copying and pasting
among different programs running in a windowing system. In the X
Windowing system, for example, the `x-select-text' function takes the
string and stores it in memory operated by X. You can paste the string
in another program, such as an Xterm.
The expression looks like this:
(if interprogram-cut-function
(funcall interprogram-cut-function string (not replace))))
If an `interprogram-cut-function' exists, then Emacs executes
`funcall', which in turn calls its first argument as a function and
passes the remaining arguments to it. (Incidentally, as far as I can
see, this `if' expression could be replaced by an `and' expression
similar to the one in the first part of the function.)
We are not going to discuss windowing systems and other programs
further, but merely note that this is a mechanism that enables GNU
Emacs to work easily and well with other programs.
This code for placing text in the kill ring, either concatenated with
an existing element or as a new element, leads us to the code for
bringing back text that has been cut out of the buffer--the yank
commands. However, before discussing the yank commands, it is better
to learn how lists are implemented in a computer. This will make clear
such mysteries as the use of the term `pointer'.
File: emacs-lisp-intro.info, Node: cons & search-fwd Review, Next: search Exercises, Prev: copy-region-as-kill, Up: Cutting & Storing Text
Review
======
Here is a brief summary of some recently introduced functions.
`car'
`cdr'
`car' returns the first element of a list; `cdr' returns the
second and subsequent elements of a list.
For example:
(car '(1 2 3 4 5 6 7))
=> 1
(cdr '(1 2 3 4 5 6 7))
=> (2 3 4 5 6 7)
`cons'
`cons' constructs a list by prepending its first argument to its
second argument.
For example:
(cons 1 '(2 3 4))
=> (1 2 3 4)
`nthcdr'
Return the result of taking CDR `n' times on a list. The `rest of
the rest', as it were.
For example:
(nthcdr 3 '(1 2 3 4 5 6 7))
=> (4 5 6 7)
`setcar'
`setcdr'
`setcar' changes the first element of a list; `setcdr' changes the
second and subsequent elements of a list.
For example:
(setq triple '(1 2 3))
(setcar triple '37)
triple
=> (37 2 3)
(setcdr triple '("foo" "bar"))
triple
=> (37 "foo" "bar")
`progn'
Evaluate each argument in sequence and then return the value of the
last.
For example:
(progn 1 2 3 4)
=> 4
`save-restriction'
Record whatever narrowing is in effect in the current buffer, if
any, and restore that narrowing after evaluating the arguments.
`search-forward'
Search for a string, and if the string is found, move point.
Takes four arguments:
1. The string to search for.
2. Optionally, the limit of the search.
3. Optionally, what to do if the search fails, return `nil' or an
error message.
4. Optionally, how many times to repeat the search; if negative,
the search goes backwards.
`kill-region'
`delete-region'
`copy-region-as-kill'
`kill-region' cuts the text between point and mark from the buffer
and stores that text in the kill ring, so you can get it back by
yanking.
`delete-and-extract-region' removes the text between point and
mark from the buffer and throws it away. You cannot get it back.
`copy-region-as-kill' copies the text between point and mark into
the kill ring, from which you can get it by yanking. The function
does not cut or remove the text from the buffer.
File: emacs-lisp-intro.info, Node: search Exercises, Prev: cons & search-fwd Review, Up: Cutting & Storing Text
Searching Exercises
===================
* Write an interactive function that searches for a string. If the
search finds the string, leave point after it and display a message
that says "Found!". (Do not use `search-forward' for the name of
this function; if you do, you will overwrite the existing version
of `search-forward' that comes with Emacs. Use a name such as
`test-search' instead.)
* Write a function that prints the third element of the kill ring in
the echo area, if any; if the kill ring does not contain a third
element, print an appropriate message.
File: emacs-lisp-intro.info, Node: List Implementation, Next: Yanking, Prev: Cutting & Storing Text, Up: Top
How Lists are Implemented
*************************
In Lisp, atoms are recorded in a straightforward fashion; if the
implementation is not straightforward in practice, it is, nonetheless,
straightforward in theory. The atom `rose', for example, is recorded
as the four contiguous letters `r', `o', `s', `e'. A list, on the
other hand, is kept differently. The mechanism is equally simple, but
it takes a moment to get used to the idea. A list is kept using a
series of pairs of pointers. In the series, the first pointer in each
pair points to an atom or to another list, and the second pointer in
each pair points to the next pair, or to the symbol `nil', which marks
the end of the list.
A pointer itself is quite simply the electronic address of what is
pointed to. Hence, a list is kept as a series of electronic addresses.
* Menu:
* Lists diagrammed::
* Symbols as Chest:: Exploring a powerful metaphor.
* List Exercise::
File: emacs-lisp-intro.info, Node: Lists diagrammed, Next: Symbols as Chest, Prev: List Implementation, Up: List Implementation
Lists diagrammed
================
For example, the list `(rose violet buttercup)' has three elements,
`rose', `violet', and `buttercup'. In the computer, the electronic
address of `rose' is recorded in a segment of computer memory along
with the address that gives the electronic address of where the atom
`violet' is located; and that address (the one that tells where
`violet' is located) is kept along with an address that tells where the
address for the atom `buttercup' is located.
This sounds more complicated than it is and is easier seen in a
diagram:
___ ___ ___ ___ ___ ___
|___|___|--> |___|___|--> |___|___|--> nil
| | |
| | |
--> rose --> violet --> buttercup
In the diagram, each box represents a word of computer memory that
holds a Lisp object, usually in the form of a memory address. The
boxes, i.e. the addresses, are in pairs. Each arrow points to what the
address is the address of, either an atom or another pair of addresses.
The first box is the electronic address of `rose' and the arrow points
to `rose'; the second box is the address of the next pair of boxes, the
first part of which is the address of `violet' and the second part of
which is the address of the next pair. The very last box points to the
symbol `nil', which marks the end of the list.
When a variable is set to a list with a function such as `setq', it
stores the address of the first box in the variable. Thus, evaluation
of the expression
(setq bouquet '(rose violet buttercup))
creates a situation like this:
bouquet
|
| ___ ___ ___ ___ ___ ___
--> |___|___|--> |___|___|--> |___|___|--> nil
| | |
| | |
--> rose --> violet --> buttercup
In this example, the symbol `bouquet' holds the address of the first
pair of boxes.
This same list can be illustrated in a different sort of box notation
like this:
bouquet
|
| -------------- --------------- ----------------
| | car | cdr | | car | cdr | | car | cdr |
-->| rose | o------->| violet | o------->| butter- | nil |
| | | | | | | cup | |
-------------- --------------- ----------------
(Symbols consist of more than pairs of addresses, but the structure
of a symbol is made up of addresses. Indeed, the symbol `bouquet'
consists of a group of address-boxes, one of which is the address of
the printed word `bouquet', a second of which is the address of a
function definition attached to the symbol, if any, a third of which is
the address of the first pair of address-boxes for the list `(rose
violet buttercup)', and so on. Here we are showing that the symbol's
third address-box points to the first pair of address-boxes for the
list.)
If a symbol is set to the CDR of a list, the list itself is not
changed; the symbol simply has an address further down the list. (In
the jargon, CAR and CDR are `non-destructive'.) Thus, evaluation of
the following expression
(setq flowers (cdr bouquet))
produces this:
bouquet flowers
| |
| ___ ___ | ___ ___ ___ ___
--> | | | --> | | | | | |
|___|___|----> |___|___|--> |___|___|--> nil
| | |
| | |
--> rose --> violet --> buttercup
The value of `flowers' is `(violet buttercup)', which is to say, the
symbol `flowers' holds the address of the pair of address-boxes, the
first of which holds the address of `violet', and the second of which
holds the address of `buttercup'.
A pair of address-boxes is called a "cons cell" or "dotted pair".
*Note List Type: (elisp)List Type, and *Note Dotted Pair Notation:
(elisp)Dotted Pair Notation, for more information about cons cells and
dotted pairs.
The function `cons' adds a new pair of addresses to the front of a
series of addresses like that shown above. For example, evaluating the
expression
(setq bouquet (cons 'lily bouquet))
produces:
bouquet flowers
| |
| ___ ___ ___ ___ | ___ ___ ___ ___
--> | | | | | | --> | | | | | |
|___|___|----> |___|___|----> |___|___|---->|___|___|--> nil
| | | |
| | | |
--> lily --> rose --> violet --> buttercup
However, this does not change the value of the symbol `flowers', as you
can see by evaluating the following,
(eq (cdr (cdr bouquet)) flowers)
which returns `t' for true.
Until it is reset, `flowers' still has the value `(violet
buttercup)'; that is, it has the address of the cons cell whose first
address is of `violet'. Also, this does not alter any of the
pre-existing cons cells; they are all still there.
Thus, in Lisp, to get the CDR of a list, you just get the address of
the next cons cell in the series; to get the CAR of a list, you get the
address of the first element of the list; to `cons' a new element on a
list, you add a new cons cell to the front of the list. That is all
there is to it! The underlying structure of Lisp is brilliantly simple!
And what does the last address in a series of cons cells refer to?
It is the address of the empty list, of `nil'.
In summary, when a Lisp variable is set to a value, it is provided
with the address of the list to which the variable refers.
File: emacs-lisp-intro.info, Node: Symbols as Chest, Next: List Exercise, Prev: Lists diagrammed, Up: List Implementation
Symbols as a Chest of Drawers
=============================
In an earlier section, I suggested that you might imagine a symbol as
being a chest of drawers. The function definition is put in one
drawer, the value in another, and so on. What is put in the drawer
holding the value can be changed without affecting the contents of the
drawer holding the function definition, and vice-versa.
Actually, what is put in each drawer is the address of the value or
function definition. It is as if you found an old chest in the attic,
and in one of its drawers you found a map giving you directions to
where the buried treasure lies.
(In addition to its name, symbol definition, and variable value, a
symbol has a `drawer' for a "property list" which can be used to record
other information. Property lists are not discussed here; see *Note
Property Lists: (elisp)Property Lists.)
Here is a fanciful representation:
Chest of Drawers Contents of Drawers
__ o0O0o __
/ \
---------------------
| directions to | [map to]
| symbol name | bouquet
| |
+---------------------+
| directions to |
| symbol definition | [none]
| |
+---------------------+
| directions to | [map to]
| variable value | (rose violet buttercup)
| |
+---------------------+
| directions to |
| property list | [not described here]
| |
+---------------------+
|/ \|
File: emacs-lisp-intro.info, Node: List Exercise, Prev: Symbols as Chest, Up: List Implementation
Exercise
========
Set `flowers' to `violet' and `buttercup'. Cons two more flowers on
to this list and set this new list to `more-flowers'. Set the CAR of
`flowers' to a fish. What does the `more-flowers' list now contain?
File: emacs-lisp-intro.info, Node: Yanking, Next: Loops & Recursion, Prev: List Implementation, Up: Top
Yanking Text Back
*****************
Whenever you cut text out of a buffer with a `kill' command in GNU
Emacs, you can bring it back with a `yank' command. The text that is
cut out of the buffer is put in the kill ring and the yank commands
insert the appropriate contents of the kill ring back into a buffer
(not necessarily the original buffer).
A simple `C-y' (`yank') command inserts the first item from the kill
ring into the current buffer. If the `C-y' command is followed
immediately by `M-y', the first element is replaced by the second
element. Successive `M-y' commands replace the second element with the
third, fourth, or fifth element, and so on. When the last element in
the kill ring is reached, it is replaced by the first element and the
cycle is repeated. (Thus the kill ring is called a `ring' rather than
just a `list'. However, the actual data structure that holds the text
is a list. *Note Handling the Kill Ring: Kill Ring, for the details of
how the list is handled as a ring.)
* Menu:
* Kill Ring Overview:: The kill ring is a list.
* kill-ring-yank-pointer:: The `kill-ring-yank-pointer' variable.
* yank nthcdr Exercises::
File: emacs-lisp-intro.info, Node: Kill Ring Overview, Next: kill-ring-yank-pointer, Prev: Yanking, Up: Yanking
Kill Ring Overview
==================
The kill ring is a list of textual strings. This is what it looks
like:
("some text" "a different piece of text" "yet more text")
If this were the contents of my kill ring and I pressed `C-y', the
string of characters saying `some text' would be inserted in this
buffer where my cursor is located.
The `yank' command is also used for duplicating text by copying it.
The copied text is not cut from the buffer, but a copy of it is put on
the kill ring and is inserted by yanking it back.
Three functions are used for bringing text back from the kill ring:
`yank', which is usually bound to `C-y'; `yank-pop', which is usually
bound to `M-y'; and `rotate-yank-pointer', which is used by the two
other functions.
These functions refer to the kill ring through a variable called the
`kill-ring-yank-pointer'. Indeed, the insertion code for both the
`yank' and `yank-pop' functions is:
(insert (car kill-ring-yank-pointer))
To begin to understand how `yank' and `yank-pop' work, it is first
necessary to look at the `kill-ring-yank-pointer' variable and the
`rotate-yank-pointer' function.
File: emacs-lisp-intro.info, Node: kill-ring-yank-pointer, Next: yank nthcdr Exercises, Prev: Kill Ring Overview, Up: Yanking
The `kill-ring-yank-pointer' Variable
=====================================
`kill-ring-yank-pointer' is a variable, just as `kill-ring' is a
variable. It points to something by being bound to the value of what
it points to, like any other Lisp variable.
Thus, if the value of the kill ring is:
("some text" "a different piece of text" "yet more text")
and the `kill-ring-yank-pointer' points to the second clause, the value
of `kill-ring-yank-pointer' is:
("a different piece of text" "yet more text")
As explained in the previous chapter (*note List Implementation::),
the computer does not keep two different copies of the text being
pointed to by both the `kill-ring' and the `kill-ring-yank-pointer'.
The words "a different piece of text" and "yet more text" are not
duplicated. Instead, the two Lisp variables point to the same pieces of
text. Here is a diagram:
kill-ring kill-ring-yank-pointer
| |
| ___ ___ | ___ ___ ___ ___
---> | | | --> | | | | | |
|___|___|----> |___|___|--> |___|___|--> nil
| | |
| | |
| | --> "yet more text"
| |
| --> "a different piece of text
|
--> "some text"
Both the variable `kill-ring' and the variable
`kill-ring-yank-pointer' are pointers. But the kill ring itself is
usually described as if it were actually what it is composed of. The
`kill-ring' is spoken of as if it were the list rather than that it
points to the list. Conversely, the `kill-ring-yank-pointer' is spoken
of as pointing to a list.
These two ways of talking about the same thing sound confusing at
first but make sense on reflection. The kill ring is generally thought
of as the complete structure of data that holds the information of what
has recently been cut out of the Emacs buffers. The
`kill-ring-yank-pointer' on the other hand, serves to indicate--that
is, to `point to'--that part of the kill ring of which the first
element (the CAR) will be inserted.
The `rotate-yank-pointer' function changes the element in the kill
ring to which the `kill-ring-yank-pointer' points; when the pointer is
set to point to the next element beyond the end of the kill ring, it
automatically sets it to point to the first element of the kill ring.
This is how the list is transformed into a ring. The
`rotate-yank-pointer' function itself is not difficult, but contains
many details. It and the much simpler `yank' and `yank-pop' functions
are described in an appendix. *Note Handling the Kill Ring: Kill Ring.
File: emacs-lisp-intro.info, Node: yank nthcdr Exercises, Prev: kill-ring-yank-pointer, Up: Yanking
Exercises with `yank' and `nthcdr'
==================================
* Using `C-h v' (`describe-variable'), look at the value of your
kill ring. Add several items to your kill ring; look at its value
again. Using `M-y' (`yank-pop)', move all the way around the kill
ring. How many items were in your kill ring? Find the value of
`kill-ring-max'. Was your kill ring full, or could you have kept
more blocks of text within it?
* Using `nthcdr' and `car', construct a series of expressions to
return the first, second, third, and fourth elements of a list.
File: emacs-lisp-intro.info, Node: Loops & Recursion, Next: Regexp Search, Prev: Yanking, Up: Top
Loops and Recursion
*******************
Emacs Lisp has two primary ways to cause an expression, or a series
of expressions, to be evaluated repeatedly: one uses a `while' loop,
and the other uses "recursion".
Repetition can be very valuable. For example, to move forward four
sentences, you need only write a program that will move forward one
sentence and then repeat the process four times. Since a computer does
not get bored or tired, such repetitive action does not have the
deleterious effects that excessive or the wrong kinds of repetition can
have on humans.
People mostly write Emacs Lisp functions using `while' loops and
their kin; but you can use recursion, which provides a very powerful
way to think about and then to solve problems(1).
* Menu:
* while:: Causing a stretch of code to repeat.
* dolist dotimes::
* Recursion:: Causing a function to call itself.
* Looping exercise::
---------- Footnotes ----------
(1) You can write recursive functions to be frugal or wasteful of
mental or computer resources; as it happens, methods that people find
easy--that are frugal of `mental resources'--sometimes use considerable
computer resources. Emacs was designed to run on machines that we now
consider limited and its default settings are conservative. You may
want to increase the values of `max-specpdl-size' and
`max-lisp-eval-depth'. In my `.emacs' file, I set them to 15 and 30
times their default value.
File: emacs-lisp-intro.info, Node: while, Next: dolist dotimes, Prev: Loops & Recursion, Up: Loops & Recursion
`while'
=======
The `while' special form tests whether the value returned by
evaluating its first argument is true or false. This is similar to what
the Lisp interpreter does with an `if'; what the interpreter does next,
however, is different.
In a `while' expression, if the value returned by evaluating the
first argument is false, the Lisp interpreter skips the rest of the
expression (the "body" of the expression) and does not evaluate it.
However, if the value is true, the Lisp interpreter evaluates the body
of the expression and then again tests whether the first argument to
`while' is true or false. If the value returned by evaluating the
first argument is again true, the Lisp interpreter again evaluates the
body of the expression.
The template for a `while' expression looks like this:
(while TRUE-OR-FALSE-TEST
BODY...)
* Menu:
* Looping with while:: Repeat so long as test returns true.
* Loop Example:: A `while' loop that uses a list.
* print-elements-of-list:: Uses `while', `car', `cdr'.
* Incrementing Loop:: A loop with an incrementing counter.
* Decrementing Loop:: A loop with a decrementing counter.
File: emacs-lisp-intro.info, Node: Looping with while, Next: Loop Example, Prev: while, Up: while
Looping with `while'
--------------------
So long as the true-or-false-test of the `while' expression returns
a true value when it is evaluated, the body is repeatedly evaluated.
This process is called a loop since the Lisp interpreter repeats the
same thing again and again, like an airplane doing a loop. When the
result of evaluating the true-or-false-test is false, the Lisp
interpreter does not evaluate the rest of the `while' expression and
`exits the loop'.
Clearly, if the value returned by evaluating the first argument to
`while' is always true, the body following will be evaluated again and
again ... and again ... forever. Conversely, if the value returned is
never true, the expressions in the body will never be evaluated. The
craft of writing a `while' loop consists of choosing a mechanism such
that the true-or-false-test returns true just the number of times that
you want the subsequent expressions to be evaluated, and then have the
test return false.
The value returned by evaluating a `while' is the value of the
true-or-false-test. An interesting consequence of this is that a
`while' loop that evaluates without error will return `nil' or false
regardless of whether it has looped 1 or 100 times or none at all. A
`while' expression that evaluates successfully never returns a true
value! What this means is that `while' is always evaluated for its
side effects, which is to say, the consequences of evaluating the
expressions within the body of the `while' loop. This makes sense. It
is not the mere act of looping that is desired, but the consequences of
what happens when the expressions in the loop are repeatedly evaluated.
File: emacs-lisp-intro.info, Node: Loop Example, Next: print-elements-of-list, Prev: Looping with while, Up: while
A `while' Loop and a List
-------------------------
A common way to control a `while' loop is to test whether a list has
any elements. If it does, the loop is repeated; but if it does not,
the repetition is ended. Since this is an important technique, we will
create a short example to illustrate it.
A simple way to test whether a list has elements is to evaluate the
list: if it has no elements, it is an empty list and will return the
empty list, `()', which is a synonym for `nil' or false. On the other
hand, a list with elements will return those elements when it is
evaluated. Since Emacs Lisp considers as true any value that is not
`nil', a list that returns elements will test true in a `while' loop.
For example, you can set the variable `empty-list' to `nil' by
evaluating the following `setq' expression:
(setq empty-list ())
After evaluating the `setq' expression, you can evaluate the variable
`empty-list' in the usual way, by placing the cursor after the symbol
and typing `C-x C-e'; `nil' will appear in your echo area:
empty-list
On the other hand, if you set a variable to be a list with elements,
the list will appear when you evaluate the variable, as you can see by
evaluating the following two expressions:
(setq animals '(gazelle giraffe lion tiger))
animals
Thus, to create a `while' loop that tests whether there are any
items in the list `animals', the first part of the loop will be written
like this:
(while animals
...
When the `while' tests its first argument, the variable `animals' is
evaluated. It returns a list. So long as the list has elements, the
`while' considers the results of the test to be true; but when the list
is empty, it considers the results of the test to be false.
To prevent the `while' loop from running forever, some mechanism
needs to be provided to empty the list eventually. An oft-used
technique is to have one of the subsequent forms in the `while'
expression set the value of the list to be the CDR of the list. Each
time the `cdr' function is evaluated, the list will be made shorter,
until eventually only the empty list will be left. At this point, the
test of the `while' loop will return false, and the arguments to the
`while' will no longer be evaluated.
For example, the list of animals bound to the variable `animals' can
be set to be the CDR of the original list with the following expression:
(setq animals (cdr animals))
If you have evaluated the previous expressions and then evaluate this
expression, you will see `(giraffe lion tiger)' appear in the echo
area. If you evaluate the expression again, `(lion tiger)' will appear
in the echo area. If you evaluate it again and yet again, `(tiger)'
appears and then the empty list, shown by `nil'.
A template for a `while' loop that uses the `cdr' function
repeatedly to cause the true-or-false-test eventually to test false
looks like this:
(while TEST-WHETHER-LIST-IS-EMPTY
BODY...
SET-LIST-TO-CDR-OF-LIST)
This test and use of `cdr' can be put together in a function that
goes through a list and prints each element of the list on a line of its
own.
File: emacs-lisp-intro.info, Node: print-elements-of-list, Next: Incrementing Loop, Prev: Loop Example, Up: while
An Example: `print-elements-of-list'
------------------------------------
The `print-elements-of-list' function illustrates a `while' loop
with a list.
The function requires several lines for its output. If you are
reading this in Emacs 21 or a later version, you can evaluate the
following expression inside of Info, as usual.
If you are using an earlier version of Emacs, you need to copy the
necessary expressions to your `*scratch*' buffer and evaluate them
there. This is because the echo area had only one line in the earlier
versions.
You can copy the expressions by marking the beginning of the region
with `C-<SPC>' (`set-mark-command'), moving the cursor to the end of
the region and then copying the region using `M-w'
(`copy-region-as-kill'). In the `*scratch*' buffer, you can yank the
expressions back by typing `C-y' (`yank').
After you have copied the expressions to the `*scratch*' buffer,
evaluate each expression in turn. Be sure to evaluate the last
expression, `(print-elements-of-list animals)', by typing `C-u C-x
C-e', that is, by giving an argument to `eval-last-sexp'. This will
cause the result of the evaluation to be printed in the `*scratch*'
buffer instead of being printed in the echo area. (Otherwise you will
see something like this in your echo area:
`^Jgiraffe^J^Jgazelle^J^Jlion^J^Jtiger^Jnil', in which each `^J' stands
for a `newline'.)
If you are using Emacs 21 or later, you can evaluate these
expressions directly in the Info buffer, and the echo area will grow to
show the results.
(setq animals '(gazelle giraffe lion tiger))
(defun print-elements-of-list (list)
"Print each element of LIST on a line of its own."
(while list
(print (car list))
(setq list (cdr list))))
(print-elements-of-list animals)
When you evaluate the three expressions in sequence, you will see this:
giraffe
gazelle
lion
tiger
nil
Each element of the list is printed on a line of its own (that is
what the function `print' does) and then the value returned by the
function is printed. Since the last expression in the function is the
`while' loop, and since `while' loops always return `nil', a `nil' is
printed after the last element of the list.
File: emacs-lisp-intro.info, Node: Incrementing Loop, Next: Decrementing Loop, Prev: print-elements-of-list, Up: while
A Loop with an Incrementing Counter
-----------------------------------
A loop is not useful unless it stops when it ought. Besides
controlling a loop with a list, a common way of stopping a loop is to
write the first argument as a test that returns false when the correct
number of repetitions are complete. This means that the loop must have
a counter--an expression that counts how many times the loop repeats
itself.
The test can be an expression such as `(< count desired-number)'
which returns `t' for true if the value of `count' is less than the
`desired-number' of repetitions and `nil' for false if the value of
`count' is equal to or is greater than the `desired-number'. The
expression that increments the count can be a simple `setq' such as
`(setq count (1+ count))', where `1+' is a built-in function in Emacs
Lisp that adds 1 to its argument. (The expression `(1+ count)' has the
same result as `(+ count 1)', but is easier for a human to read.)
The template for a `while' loop controlled by an incrementing
counter looks like this:
SET-COUNT-TO-INITIAL-VALUE
(while (< count desired-number) ; true-or-false-test
BODY...
(setq count (1+ count))) ; incrementer
Note that you need to set the initial value of `count'; usually it is
set to 1.
* Menu:
* Incrementing Example:: Counting pebbles in a triangle.
* Inc Example parts:: The parts of the function definition.
* Inc Example altogether:: Putting the function definition together.
File: emacs-lisp-intro.info, Node: Incrementing Example, Next: Inc Example parts, Prev: Incrementing Loop, Up: Incrementing Loop
Example with incrementing counter
.................................
Suppose you are playing on the beach and decide to make a triangle of
pebbles, putting one pebble in the first row, two in the second row,
three in the third row and so on, like this:
*
* *
* * *
* * * *
(About 2500 years ago, Pythagoras and others developed the beginnings of
number theory by considering questions such as this.)
Suppose you want to know how many pebbles you will need to make a
triangle with 7 rows?
Clearly, what you need to do is add up the numbers from 1 to 7.
There are two ways to do this; start with the smallest number, one, and
add up the list in sequence, 1, 2, 3, 4 and so on; or start with the
largest number and add the list going down: 7, 6, 5, 4 and so on.
Because both mechanisms illustrate common ways of writing `while'
loops, we will create two examples, one counting up and the other
counting down. In this first example, we will start with 1 and add 2,
3, 4 and so on.
If you are just adding up a short list of numbers, the easiest way
to do it is to add up all the numbers at once. However, if you do not
know ahead of time how many numbers your list will have, or if you want
to be prepared for a very long list, then you need to design your
addition so that what you do is repeat a simple process many times
instead of doing a more complex process once.
For example, instead of adding up all the pebbles all at once, what
you can do is add the number of pebbles in the first row, 1, to the
number in the second row, 2, and then add the total of those two rows
to the third row, 3. Then you can add the number in the fourth row, 4,
to the total of the first three rows; and so on.
The critical characteristic of the process is that each repetitive
action is simple. In this case, at each step we add only two numbers,
the number of pebbles in the row and the total already found. This
process of adding two numbers is repeated again and again until the last
row has been added to the total of all the preceding rows. In a more
complex loop the repetitive action might not be so simple, but it will
be simpler than doing everything all at once.
File: emacs-lisp-intro.info, Node: Inc Example parts, Next: Inc Example altogether, Prev: Incrementing Example, Up: Incrementing Loop
The parts of the function definition
....................................
The preceding analysis gives us the bones of our function definition:
first, we will need a variable that we can call `total' that will be
the total number of pebbles. This will be the value returned by the
function.
Second, we know that the function will require an argument: this
argument will be the total number of rows in the triangle. It can be
called `number-of-rows'.
Finally, we need a variable to use as a counter. We could call this
variable `counter', but a better name is `row-number'. That is because
what the counter does is count rows, and a program should be written to
be as understandable as possible.
When the Lisp interpreter first starts evaluating the expressions in
the function, the value of `total' should be set to zero, since we have
not added anything to it. Then the function should add the number of
pebbles in the first row to the total, and then add the number of
pebbles in the second to the total, and then add the number of pebbles
in the third row to the total, and so on, until there are no more rows
left to add.
Both `total' and `row-number' are used only inside the function, so
they can be declared as local variables with `let' and given initial
values. Clearly, the initial value for `total' should be 0. The
initial value of `row-number' should be 1, since we start with the
first row. This means that the `let' statement will look like this:
(let ((total 0)
(row-number 1))
BODY...)
After the internal variables are declared and bound to their initial
values, we can begin the `while' loop. The expression that serves as
the test should return a value of `t' for true so long as the
`row-number' is less than or equal to the `number-of-rows'. (If the
expression tests true only so long as the row number is less than the
number of rows in the triangle, the last row will never be added to the
total; hence the row number has to be either less than or equal to the
number of rows.)
Lisp provides the `<=' function that returns true if the value of
its first argument is less than or equal to the value of its second
argument and false otherwise. So the expression that the `while' will
evaluate as its test should look like this:
(<= row-number number-of-rows)
The total number of pebbles can be found by repeatedly adding the
number of pebbles in a row to the total already found. Since the
number of pebbles in the row is equal to the row number, the total can
be found by adding the row number to the total. (Clearly, in a more
complex situation, the number of pebbles in the row might be related to
the row number in a more complicated way; if this were the case, the
row number would be replaced by the appropriate expression.)
(setq total (+ total row-number))
What this does is set the new value of `total' to be equal to the sum
of adding the number of pebbles in the row to the previous total.
After setting the value of `total', the conditions need to be
established for the next repetition of the loop, if there is one. This
is done by incrementing the value of the `row-number' variable, which
serves as a counter. After the `row-number' variable has been
incremented, the true-or-false-test at the beginning of the `while'
loop tests whether its value is still less than or equal to the value
of the `number-of-rows' and if it is, adds the new value of the
`row-number' variable to the `total' of the previous repetition of the
loop.
The built-in Emacs Lisp function `1+' adds 1 to a number, so the
`row-number' variable can be incremented with this expression:
(setq row-number (1+ row-number))